package com.vehicle.utils;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.vehicle.constants.Constants;
import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Base64;

/**
 * 图片与 Base64 编码转换工具类
 * <p>
 * 提供图片文件与 Base64 编码之间的互转功能，
 * 支持自动压缩图片至指定大小以下（用于上传或数据上报场景）。
 * </p>
 *
 * <p>主要功能：</p>
 * <ul>
 *   <li>将本地图片文件转换为 Base64 字符串；</li>
 *   <li>自动压缩图片尺寸以控制文件大小；</li>
 *   <li>支持自定义最大字节数限制。</li>
 * </ul>
 */
@Slf4j
public class Base64ToImageUtil {


    // 保存图片到本地
    public static String saveBase64(String base64String, String fileDir) {

        if (StrUtil.isEmpty(fileDir)) {
            fileDir = Constants.PICTURE_FILE_DETECTED_PATH;
        }
        String filePath = String.join(File.separator, fileDir , IdUtil.simpleUUID() + ".jpeg");

        //把base64转位图片 存到电脑本地 得到一个路径
        try {
            Base64ToImageUtil.saveBase64ImageToFile(base64String, filePath);
        } catch (IOException e) {
            log.error("记录台账 图片保存失败", e);
            return null;
        }

        return filePath;
    }


    // 将base64字符串保存为图片文件
    public static void saveBase64ImageToFile(String base64String, String filePath) throws IOException {
        if (StrUtil.isEmpty(base64String)) {
            log.info("[Base64ImageToFile] base64String is null filePath:{}", filePath);
        }
        byte[] imageBytes = decodeBase64(base64String);
        saveImage(imageBytes, filePath);
    }


    // 将base64字符串转换为字节数组
    public static byte[] decodeBase64(String base64String) {
        return Base64.getDecoder().decode(base64String);
    }

    // 将字节数组保存为文件
    public static void saveImage(byte[] imageBytes, String filePath) throws IOException {
        final File dest = new File(filePath);
        final File parentFile = dest.getParentFile();
        if (!parentFile.exists()) {
            parentFile.mkdirs();
        }
        try (FileOutputStream fos = new FileOutputStream(filePath)) {
            fos.write(imageBytes);
        }
    }

    /**
     * 图片转 Base64（默认限制为 2MB）
     *
     * @param imagePath 图片文件路径
     * @return Base64 编码字符串，若文件不存在或异常返回 null
     */
    public static String imageToBase64LimitSize(String imagePath) {
        // 调用重载方法，设置默认最大图片大小为 2MB
        return imageToBase64(imagePath, 2 * 1024 * 1024L);
    }

    /**
     * 图片转 Base64（支持压缩）
     * <p>
     * 当图片大小超过设定的最大字节数时，将自动压缩图片尺寸。
     * </p>
     *
     * @param imagePath 图片路径
     * @param maxBytes 最大允许的图片字节数（超过后会压缩）
     * @return Base64 编码字符串，异常返回 null
     */
    public static String imageToBase64(String imagePath, long maxBytes) {
        // 校验文件路径是否为空
        if (StrUtil.isEmpty(imagePath)) {
            return null;
        }
        final File file = new File(imagePath);
        // 校验文件是否存在
        if (!file.exists()) {
            log.error("[imageToBase64] File not found: {}", imagePath);
            return null;
        }

        try {
            // 读取原始图片
            final BufferedImage originalImage = ImageIO.read(file);
            final ByteArrayOutputStream baos = new ByteArrayOutputStream();
            // 若图片文件未超过最大限制，直接转换为 Base64
            if (file.length() <= maxBytes) {
                return imageToBase64(imagePath);
            }
            final long start = System.currentTimeMillis();
            // 打印日志：图片超出限制，准备压缩
            log.info("[imageToBase64] Image size is too large, max:{}, imgSize:{}, compressing: {}", maxBytes, file.length(), imagePath);
            // 如果图片大于指定的大小, 进行压缩
            // 计算缩放比例
            final double ratio = (double) maxBytes / file.length();
            final int width = (int) (originalImage.getWidth() * Math.sqrt(ratio));
            final int height = (int) (originalImage.getHeight() * Math.sqrt(ratio));

            // 创建缩放后的图片对象
            final BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            // 使用 Graphics2D 绘制缩放后的图片
            Graphics2D g = resizedImage.createGraphics();
            final Image scaledImage = originalImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
            g.drawImage(scaledImage, 0, 0, null);
            g.dispose();

            // 将压缩后的图片写入输出流
            ImageIO.write(resizedImage, "jpg", baos);
            final byte[] imageBytes = baos.toByteArray();
            final String base64 = bytesToBase64(imageBytes);
            log.info("[imageToBase64] Image compressed successfully, max:{},  imgSize:{}, afterSize:{}, cost: {}ms", maxBytes, file.length(), imageBytes.length, System.currentTimeMillis() - start);
            // 返回压缩后的 Base64 编码字符串
            return base64;
        } catch (IOException e) {
            log.error("[imageToBase64] Error converting image to Base64", e);
            return null;
        }

    }


    /**
     * 图片转 Base64（不压缩）
     *
     * @param imagePath 图片文件路径
     * @return Base64 字符串
     */
    public static String imageToBase64(String imagePath) {
        if (StrUtil.isEmpty(imagePath)) {
            return null;
        }

        return imageToBase64(new File(imagePath));
    }


    /**
     * 将文件对象转换为 Base64 编码字符串
     *
     * @param file 图片文件对象
     * @return Base64 编码字符串
     */
    public static String imageToBase64(File file) {
        try (FileInputStream imageInFile = new FileInputStream(file)) {
            // 分配字节数组大小，与文件长度相同
            byte[] imageData = new byte[(int) file.length()];
            imageInFile.read(imageData);

            // 调用编码方法将图片字节转换为 Base64 字符串
            return bytesToBase64(imageData);
        } catch (Exception e) {
            log.error("[imageToBase64] error. msg:{}", e.getMessage());
            return null;
        }
    }

    /**
     * 字节数组转 Base64 编码
     *
     * @param data 图片字节数组
     * @return Base64 字符串
     */
    public static String bytesToBase64(byte[] data) {
        // 使用 JDK 自带的 Base64 编码器进行编码
        return Base64.getEncoder().encodeToString(data);
    }
}
